/*******************************************************************************
 * Copyright (c) 2014 IBM Corp.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v1.0 which accompany this distribution.
 *
 * The Eclipse Public License is available at
 *    http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at
 *   http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *    Ian Craggs - initial API and implementation and/or initial documentation
 *    Sergio R. Caprile - clarifications and/or documentation extension
 *******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "cmsis_os2.h"
#include "ohos_init.h"

#include "MQTTClient.h"
#include "wifi_sta_connect.h"

#include "cJSON.h"

#include "iot_uart.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"

// #include "temp_data.h"
// #include "motor.h"
// #include "light.h"

#define LED7 7


static unsigned char sendBuf[1000];
static unsigned char readBuf[1000];

#define WIFI_SSID "MY_SW"
#define WIFI_PWD "12345678"

#define HOST_ADDR "bf4c40ad8d.st1.iotda-device.cn-north-4.myhuaweicloud.com"

#define Device_Id "67683a6aef99673c8ad854d7_1234abcd"

#define PUBLISH_TOPIC "$oc/devices/"Device_Id"/sys/properties/report"
#define SUBCRIB_TOPIC "$oc/devices/"Device_Id"/sys/commands/#" ///request_id={request_id}"
#define RESPONSE_TOPIC "$oc/devices/"Device_Id"/sys/commands/response" ///request_id={request_id}"


Network network;
MQTTClient client;

#define WIFI_IOT_UART_IDX 1

unsigned char uartWriteBuff[] = "hello uart!";
unsigned char uartReadBuff[1024] = {0};

static int uart_recv = 0;
int usr_uart_config(void)
{
    int ret;
    // IoTGpioInit(11);
    // IoTGpioInit(12);
    // IoTGpioSetFunc(11, IOT_GPIO_FUNC_GPIO_11_UART2_TXD);
    // IoTGpioSetFunc(12, IOT_GPIO_FUNC_GPIO_12_UART2_RXD);
    // 初始化UART配置，115200，数据bit为8,停止位1，奇偶校验为NONE，流控为NONE
    IotUartAttribute uart_attr = {

        .baudRate = 115200,

        //data_bits: 8bits
        .dataBits = 8,
        .stopBits = 1,
        .parity = 0,
        .rxBlock = 1,
    };
    IoTUartDeinit(WIFI_IOT_UART_IDX);
    ret = IoTUartInit(WIFI_IOT_UART_IDX, &uart_attr);
    if (ret != 0) {
        printf("uart init fail ret = %d\r\n",ret);
    }
    return ret;
}
 
 
// 1.任务处理函数
static void* UartDemo_Task(const char* arg)
{
     int len = 0;
 
    (void)arg;
    printf("[UartDemo] UartDemo_Task()\n");
 
    // IoTGpioInit(); // 使用GPIO，都需要调用该接口
    printf("UART init...\r\n");
    usr_uart_config();

    // IoTUartWrite(WIFI_IOT_UART_IDX, (unsigned char *)uartWriteBuff, sizeof(uartWriteBuff));
    while (1) {
        len = IoTUartRead(WIFI_IOT_UART_IDX, uartReadBuff, sizeof(uartReadBuff));
        if (len > 0) {
            printf("Uart read data%d:%s",len, uartReadBuff);
            uart_recv = len;
        }
        // usleep(1000000);
    }
    return NULL;
}

// #define CONFIG_SERVER_IP            "192.168.43.144"                     // 要连接的服务器IP
#define CONFIG_SERVER_IP            "192.168.43.92"                     // 要连接的服务器IP
#define CONFIG_SERVER_PORT          3861                                // 要连接的服务器端口

int sock_fd = -1;
static struct sockaddr_in g_send_addr;

int udp_send_data(uint8_t *data,int datalen){
    if(sock_fd < 0){
        return;
    }
    struct sockaddr_in send_addr;
    socklen_t addr_length = sizeof(send_addr);
      // 初始化预连接的服务端地址
    send_addr.sin_family = AF_INET;
    send_addr.sin_port = htons(CONFIG_SERVER_PORT);
    send_addr.sin_addr.s_addr = inet_addr(CONFIG_SERVER_IP);//g_send_addr.sin_addr.s_addr;
    addr_length = sizeof(send_addr);

    //  bzero(recvBuf, sizeof(recvBuf));

    // 发送数据到服务远端
    printf("sendto start!\r\n");
    int n = sendto(sock_fd, data, datalen, 0, (struct sockaddr *)&send_addr, addr_length);
    printf("sendto end!\r\n");
    
    return n;
}


void UDP_TASK(){
  
    //服务端地址信息
	struct sockaddr_in server_sock;

    //创建socket
	if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
	{
		perror("socket is error.\r\n");
		return -1;
	}

    printf("=== > sock_fd=%d\n",sock_fd);
    // const int opt=-1;
    // //设置套接字类型
    //  int nb=setsockopt(sock_fd,SOL_SOCKET,SO_BROADCAST,(char*)&opt,sizeof(opt));
    //  printf("=== > nb=%d\n",nb);
    //  if(nb< 0)
    //  {
    //      printf("set socket error...\n");
    //     //  return -1;
    //  }

	bzero(&server_sock, sizeof(server_sock));
	server_sock.sin_family = AF_INET;
	server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
	server_sock.sin_port = htons(3861);

	//调用bind函数绑定socket和地址
	if (bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)) == -1)
	{
		perror("bind is error.\r\n");
		return -1;
	}

    int ret;

    //客户端地址信息
    // struct sockaddr_in send_addr;
    int size_send_addr= sizeof(struct sockaddr_in);
    // send_addr.sin_family = AF_INET;
    // send_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    // send_addr.sin_port = htons(3861);

    while (1)
    {
        printf("UDP wait:\r\n");
        bzero(uartReadBuff, sizeof(uartReadBuff));
        //接收数据
        ret = recvfrom(sock_fd, uartReadBuff, sizeof(uartReadBuff), 0, 
        (struct sockaddr *)&g_send_addr, &size_send_addr);
        // if (ret >0)
        // {
            printf("UDP recv%d:%s\r\n",ret ,uartReadBuff);
            uart_recv = ret;
            // return -1;
        // }
       
    }
}


void messageArrived(MessageData* data)
{
    int rc;
    printf("Message arrived on topic %.*s: %.*s\n", data->topicName->lenstring.len, data->topicName->lenstring.data,
           data->message->payloadlen, data->message->payload);

    /*
        /xx//x/x//x/requets_id=123456
    */
/*
topic $oc/devices/szdx234/sys/commands/request_id=40ae7e8e-e4d9-46ac-b323-6b75f2939bf4: 

*/
   //get request id
    char *request_id_idx=NULL;
    char request_id[48]={0};
    request_id_idx = strstr(data->topicName->lenstring.data,"request_id=");
    strncpy(request_id,request_id_idx+11,36);
    printf("request_id = %s\n",request_id);

    //create response topic
    char rsptopic[128]={0};
    sprintf(rsptopic,"%s/request_id=%s",RESPONSE_TOPIC,request_id);
    printf("rsptopic = %s\n",rsptopic);

    //response message
    MQTTMessage message;
    char payload[300];
    message.qos = 0;
    message.retained = 0;
    message.payload = payload;
    sprintf(payload, "{ \
    \"result_code\": 0, \
    \"response_name\": \"COMMAND_RESPONSE\", \
    \"paras\": { \
        \"result\": \"success\" \
    } \
    }" );
    message.payloadlen = strlen(payload);

    //publish the msg to responese topic
    if ((rc = MQTTPublish(&client, rsptopic, &message)) != 0) {
        printf("Return code from MQTT publish is %d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        
    }
    //{"paras":{"onoff":"ON"},"service_id":"smartFan","command_name":"light"}

    udp_send_data(data->message->payload,strlen(data->message->payload));
    #if 0
    cJSON *root = cJSON_Parse(data->message->payload);
    if(root != NULL){

        cJSON *cmd_name_obj = cJSON_GetObjectItem(root,"command_name");
        if(cmd_name_obj != NULL){
            char *cmd_name_str = cJSON_GetStringValue(cmd_name_obj);
            /* light   fan*/
            if(strcmp(cmd_name_str,"light_control") == 0){
                /* light cmd*/
                cJSON *paras_obj = cJSON_GetObjectItem(root,"paras");
                if(paras_obj != NULL){
                    cJSON *paras_item=cJSON_GetObjectItem(paras_obj,"onoff");
                    if(paras_item != NULL){
                        char *onoff = cJSON_GetStringValue(paras_item);
                        printf("light onoff cmd is :%s\n",onoff);

                        if(strcmp(onoff,"ON") == 0){
                            printf("turn on the light\n");
                            led_control(1);
                            
                        }else if(strcmp(onoff,"OFF") == 0){
                            printf("turn off the light\n");
                            
                            led_control(0);
                        }
                    }
                }
            }
            if(strcmp(cmd_name_str,"motor_control") == 0){
                /* light cmd*/
                cJSON *paras_obj = cJSON_GetObjectItem(root,"paras");
                if(paras_obj != NULL){
                    cJSON *paras_item=cJSON_GetObjectItem(paras_obj,"onoff");
                    if(paras_item != NULL){
                        char *onoff = cJSON_GetStringValue(paras_item);
                        printf("light onoff cmd is :%s\n",onoff);

                        if(strcmp(onoff,"ON") == 0){
                            printf("turn on the light\n");
                            fan_control(1);
                        }else if(strcmp(onoff,"OFF") == 0){
                            printf("turn off the light\n");
                            
                            fan_control(0);
                        }
                    }
                }
            }
          

        }
        cJSON_Delete(root);
    }
    #endif

   
}

extern float g_temp;
extern float g_humi;

static void MQTTDemoTask(void)
{

    printf(">> MQTTDemoTask ...\n");
    /*连接wifi*/
    WifiConnect(WIFI_SSID, WIFI_PWD);
    printf("Starting ...\n");
    int rc, count = 0;

    /*网络初始化*/
    NetworkInit(&network);
    printf("NetworkConnect  ...\n");

     osThreadAttr_t attr;

    attr.name = "UDP_TASK";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = osPriorityNormal;
    if (osThreadNew((osThreadFunc_t)UDP_TASK, NULL, &attr) == NULL) {
        printf("[MQTT_Demo] Failed to create UDP_TASK!\n");
    }
begin:
    /* 连接网络*/
    NetworkConnect(&network, HOST_ADDR, 1883);
    printf("MQTTClientInit  ...\n");
    /*MQTT客户端初始化*/
    MQTTClientInit(&client, &network, 2000, sendBuf, sizeof(sendBuf), readBuf, sizeof(readBuf));

    MQTTString clientId = MQTTString_initializer;
    clientId.cstring = "67683a6aef99673c8ad854d7_1234abcd_0_0_2024122216";

    MQTTString userName = MQTTString_initializer;
    userName.cstring = "67683a6aef99673c8ad854d7_1234abcd"; //deviceID

    MQTTString password = MQTTString_initializer;
    password.cstring = "7fb2f877c987133bec600ded1f348ddb69a0da8f9e8f5fb404c911e7a3888642";

    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    data.clientID = clientId;

    data.username = userName;
	data.password = password;

    data.willFlag = 0;
    data.MQTTVersion = 4;
    data.keepAliveInterval = 60;
    data.cleansession = 1;

    printf("MQTTConnect  ...\n");
    rc = MQTTConnect(&client, &data);
    if (rc != 0) {
        printf("MQTTConnect: %d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        osDelay(200);
        goto begin;
    }

    printf("MQTTSubscribe  ...\n");
    rc = MQTTSubscribe(&client, SUBCRIB_TOPIC, 0, messageArrived);

    if (rc != 0) {
        printf("MQTTSubscribe: %d\n", rc);
        osDelay(200);
        goto begin;
    }
    
    while (1) {
        float temp;
        float humi;

        // SHT3X_ReadMeasurementBuffer(&temp,&humi);
       
        MQTTMessage message;
        char *publishtopic=PUBLISH_TOPIC;

        char payload[300]={0};
     
/*
        cJSON *root = cJSON_CreateObject();


        if(root != NULL){

            cJSON *serv_arr = cJSON_AddArrayToObject(root, "services");

            cJSON *arr_item =  cJSON_CreateObject();

            cJSON_AddStringToObject(arr_item,"service_id","restroom");

            cJSON *pro_obj = cJSON_CreateObject();
            cJSON_AddItemToObject(arr_item,"properties",pro_obj);

            cJSON_AddNumberToObject(pro_obj,"temp",g_temp);
            cJSON_AddNumberToObject(pro_obj,"humi",g_humi);

            cJSON_AddItemToArray(serv_arr,arr_item);

            char *palyload_str = cJSON_PrintUnformatted(root);

            strcpy(payload,palyload_str);

            cJSON_free(palyload_str);
            cJSON_Delete(root);

        }
     */
        
        if (uart_recv > 0) {
            // printf("Uart read data%d:%s",len, payload);
            message.qos = 0;
            message.retained = 0;
            message.payload = uartReadBuff;
            // sprintf(payload, "{\"services\": [  \
            //     {\"service_id\": \"fan_serv\",  \"properties\": {\"temprature\": %02f,\"humidity\": %02f } \
            //     }   \
            //     ]}", g_temp,g_humi);
            message.payloadlen = strlen(uartReadBuff);

            if ((rc = MQTTPublish(&client, publishtopic, &message)) != 0) {
                printf("Return code from MQTT publish is %d\n", rc);
                NetworkDisconnect(&network);
                MQTTDisconnect(&client);
                goto begin;
            }else{
                printf("mqtt publish success:%s\n",payload);
            }
            uart_recv = 0;
        }
        // printf(">>wait\n");
        /*阻塞至多5000ms,有消息下发则退出阻塞*/
        MQTTYield(&client, 3000);
        // osDelay(500);
    }
}    

static void MQTTDemo(void)
{
    osThreadAttr_t attr;

    attr.name = "MQTTDemoTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = osPriorityNormal;

    if (osThreadNew((osThreadFunc_t)MQTTDemoTask, NULL, &attr) == NULL) {
        printf("[MQTT_Demo] Failed to create MQTTDemoTask!\n");
    }

   
}

APP_FEATURE_INIT(MQTTDemo);